package com.fdb.efp.limit.common.util;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fdb.basic.framework.core.util.DateTool;
import com.fdb.basic.framework.core.util.ReflectUtility;
import com.fdb.basic.framework.core.util.StringUtil;

/**
 * @ClassName ReadTxtUtil
 * @Description 写入以及写出txt文件内容
 * @author zhangyue
 * @Date 2018年5月17日 上午8:40:49
 * @version 1.0.0
 */
public class WriteTxtUtil {

	private static Logger logger = LoggerFactory.getLogger(WriteTxtUtil.class);

	/**
	 * 
	 * @Description (TODO这里用一句话描述这个方法的作用)
	 * @param file
	 *            需要解析的文件
	 * @param clazz
	 *            需要把解析的文件转换成的类
	 * @param operation
	 *            分隔符
	 * @return
	 */
	@SuppressWarnings({ "resource", "unchecked" })
	public static <T> List<T> readTxt(File file, Class<? extends T> clazz, String operation) throws Exception {
		InputStreamReader reader = null;
		try {
			if (!StringUtil.isNotEmpty(operation)) {
				throw new Exception("请传入分隔符号");
			}
			reader = new InputStreamReader(new FileInputStream(file), "UTF-8");
			BufferedReader br = new BufferedReader(reader);
			String line = "";
			line = br.readLine();
			List<T> tList = new ArrayList<T>();
			while (StringUtil.isStrNotEmpty(line)) {
				Object object = clazz.newInstance();
				object = setData(object, line, operation);
				tList.add((T) object);
				line = br.readLine();
			}
			return tList;
		} catch (UnsupportedEncodingException e) {
			logger.info("The Character Encoding is not supported:" + e);
			throw new Exception("The Character Encoding is not supported:" + e);
		} catch (FileNotFoundException e) {
			logger.info("open the file denoted by a specified pathname has failed:" + e);
			throw new Exception("open the file denoted by a specified pathname has failed:" + e);
		} catch (IOException e) {
			logger.info("I/O operations has faile:" + e);
			throw new Exception("I/O operations has faile:" + e);
		} catch (IllegalArgumentException e) {
			logger.info(" an illegal or inappropriate argument:" + e);
			throw new Exception("an illegal or inappropriate argument:" + e);
		} catch (IllegalAccessException e) {
			logger.info(" an illegal or inappropriate access:" + e);
			throw new Exception(" an illegal or inappropriate access:" + e);
		} catch (InstantiationException e) {
			logger.info(" an illegal or inappropriate access:" + e);
			throw new Exception(" an illegal or inappropriate access:" + e);
		}
	}

	/**
	 * 
	 * @Description 将传入的list转换为 byte[]输出
	 * @param lists
	 * @return
	 */
	public static <T> byte[] writeTxt(List<T> lists, String operation) throws Exception {
		ByteArrayOutputStream byteArrayOutputStream = null;
		byte[] result = null;
		try {
			if (byteArrayOutputStream == null) {
				byteArrayOutputStream = new ByteArrayOutputStream();
			}
			if (!StringUtil.isNotEmpty(operation)) {
				throw new Exception("请传入分隔符号");
			}
			for (T t : lists) {
				String outputStr = ToStringBuilder.reflectionToString(t, ToStringStyle.NO_FIELD_NAMES_STYLE);
				outputStr = outputStr.substring(outputStr.indexOf("[") + 1, outputStr.lastIndexOf("]")).replace(",", operation)
						.replace("<null>", "");
				byteArrayOutputStream.write(outputStr.getBytes("GBK"));
				byteArrayOutputStream.write("\r\n".getBytes("GBK"));
			}
			byteArrayOutputStream.flush();
			result = byteArrayOutputStream.toByteArray();
			return result;
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new RuntimeException(e);
		} finally {
			try {
				if (byteArrayOutputStream != null) {
					byteArrayOutputStream.close();
				}
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
				throw new RuntimeException(e);
			}
		}
	}

	/**
	 * 
	 * @Description 将数据写入传入的file中
	 * @param file
	 * @param lists
	 * @return
	 * @throws Exception
	 */
	public static <T> File writeTxt(String filePath, List<T> lists, String operation) throws Exception {
		OutputStreamWriter out = null;
		FileOutputStream fos = null;
		File file = null;
		try {
			file = new File(filePath);
			if (file.exists()) {
				file.delete();
			}
			file.createNewFile();
			fos = new FileOutputStream(file);
			fos.flush();
			out = new OutputStreamWriter(fos, "GBK");
			out.flush();
			for (T t : lists) {
				String outputStr = ToStringBuilder.reflectionToString(t, ToStringStyle.NO_FIELD_NAMES_STYLE);
				outputStr = outputStr.substring(outputStr.indexOf("[") + 1, outputStr.lastIndexOf("]")).replace(",", operation)
						.replace("<null>", "");
				out.write(outputStr);
				out.write("\r\n");
			}
			logger.info("文件格式" + out.getEncoding());
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new RuntimeException(e);
		} finally {
			if (out != null) {
				out.close();
			}
			if (fos != null) {
				fos.close();
			}
		}
		return file;
	}

	/**
	 * 
	 * @Description 为每一行设置对象的值
	 * @param t
	 * @param data
	 * @return
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 */
	@SuppressWarnings("unchecked")
	private static <T> T setData(Object t, String data, String operation)
			throws IllegalArgumentException, IllegalAccessException, Exception {
		String[] dataArray = data.split("\\" + operation);
		int count = 0;
		for (String str : dataArray) {
			count++;
			Field[] fields = t.getClass().getDeclaredFields();
			if (Objects.nonNull(fields) && fields.length > 0) {
				for (int i = 0; i < fields.length; i++) {
					Field field = fields[count];
					t = changeData(t, field, str);
				}
			}
		}
		return (T) t;
	}

	/**
	 * 
	 * @Description 为field设置值
	 * @param t
	 * @param field
	 * @param data
	 * @return
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	private static Object changeData(Object t, Field field, String data) throws IllegalArgumentException, IllegalAccessException {
		if (field.getGenericType().toString().equals("class java.math.BigDecimal")) {
			if (StringUtil.isNotEmpty(data)) {
				ReflectUtility.setObjectFieldValue(t, field, new BigDecimal(data));
			}
		} else if (field.getGenericType().toString().equals("int") || field.getGenericType().toString().equals("class java.lang.Integer")) {
			ReflectUtility.setObjectFieldValue(t, field, Integer.parseInt(data));
		} else if (field.getGenericType().toString().equals("class java.lang.Long")) {
			ReflectUtility.setObjectFieldValue(t, field, Long.parseLong(data));
		} else if (field.getGenericType().toString().equals("class java.lang.Float")) {
			ReflectUtility.setObjectFieldValue(t, field, Float.parseFloat(data));
		} else if (field.getGenericType().toString().equals("class java.lang.Double")) {
			ReflectUtility.setObjectFieldValue(t, field, Double.parseDouble(data));
		} else if (field.getGenericType().toString().equals("class java.lang.Boolean")) {
			ReflectUtility.setObjectFieldValue(t, field, Boolean.parseBoolean(data));
		} else if (field.getGenericType().toString().equals("java.util.Date")) {
			ReflectUtility.setObjectFieldValue(t, field, DateTool.formatDate(data, DateTool.PATTERN_DEFAULT));
		} else {
			ReflectUtility.setObjectFieldValue(t, field, data);
		}
		return t;
	}

	/**
	 * 
	 * @Description 将一组文件打包成tar包
	 * @param sources
	 *            将要打包的文件组
	 * @param target
	 *            打包之后的文件
	 * @return 打包之后的文件
	 * @throws Exception
	 */
	public static File compressTar(File[] sources, File target) throws Exception {
		FileOutputStream out = null;
		try {
			if (target.exists()) {
				target.delete();
			}
			target.createNewFile();
			out = new FileOutputStream(target);
		} catch (FileNotFoundException e1) {
			logger.info("找不到文件" + e1);
			throw new Exception("传入的目标文件target为空");
		}
		TarArchiveOutputStream os = new TarArchiveOutputStream(out);
		for (File file : sources) {
			try {
				if (Objects.isNull(sources)) {
					continue;
				}
				os.putArchiveEntry(new TarArchiveEntry(file));
				FileInputStream fis = new FileInputStream(file);
				IOUtils.copy(fis, os);
				fis.close();
				os.closeArchiveEntry();
			} catch (FileNotFoundException e) {
				logger.info("找不到文件" + e);
				throw new Exception("传入的目标文件target为空");
			} catch (IOException e) {
				logger.info("IO错误" + e);
				throw new Exception(e);
			}
		}
		if (os != null) {
			try {
				os.flush();
				os.close();
			} catch (IOException e) {
				logger.info("IO错误" + e);
				throw new Exception(e);
			}
		}
		if (out != null) {
			try {
				out.flush();
				out.close();
			} catch (IOException e) {
				logger.info("IO错误" + e);
				throw new Exception(e);
			}
		}
		return target;
	}

}
